﻿namespace BM.Tools.WebControls.MForm
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Xml;
    using System.Xml.XPath;

    using BM.Tools.WebControls.MForm.Controls;
    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Items;

    /// <summary>
    /// A static class that allows retrieving the XML data out of the form
    /// </summary>
    public static class XmlOutput
    {
        /// <summary>
        /// looks for IXmlEditor objects inside child controls
        /// </summary>
        /// <param name="parent">
        /// The parent.
        /// </param>
        /// <returns>
        /// all children xml editors
        /// </returns>
        public static IEnumerable<IXmlEditor> GetChildrenXmlEditors(this IXmlEditor parent)
        {
            var control = parent as System.Web.UI.Control;
            if (control == null)
            {
                return null;
            }

            return control.Controls.OfType<IXmlEditor>(true).OrderBy(editor => editor.Ordinal);
        }

        /// <summary>
        /// returns the output xml (the node with all the child nodes, wrapped in an XmlDocument) associated with the given OffspringsItem
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <returns>
        /// the output xml document
        /// </returns>
        [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "Specific functionality provided by the concrete type is required")]
        public static XmlDocument GetOutputXml(this OffspringItem item)
        {
            var outputXml = new XmlDocument();
            item.AppendToParent(outputXml);
            return outputXml;
        }

        /// <summary>
        /// returns the output xml with left nodes (the node with all the child nodes, wrapped in an XmlDocument) associated with the given OffspringsItem
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <returns>
        /// the output xml document with left nodes attached
        /// </returns>
        [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "Specific functionality provided by the concrete type is required")]
        public static XmlDocument GetOutputXmlWithLeftNodes(this OffspringItem item)
        {
            var outputXml = new XmlDocument();
            item.AppendToParentWithLeftNodes(outputXml);
            return outputXml;
        }

        /// <summary>
        /// Appends xml attribute to the specified node.
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <param name="parent">
        /// The parent node.
        /// </param>        
        internal static void AppendAttribute(this LeafItem item, IXPathNavigable parent)
        {
            parent.CreateNavigator().CreateAttribute(null, item.Basis.LocalName, null, item.Value);                        
        }

        /// <summary>
        /// Appends xml element to the specified node.
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <param name="parent">
        /// The parent node.
        /// </param>        
        internal static void AppendElement(this LeafItem item, IXPathNavigable parent)
        {
            parent.CreateNavigator().AppendChildElement(item.Basis.Prefix, item.Basis.LocalName, item.Basis.Namespace, item.Value);            
        }

        internal static IXPathNavigable AppendElement(this OffspringItem item, IXPathNavigable parent)
        {
            var navigator = parent.CreateNavigator();
            navigator.AppendChildElement(item.Basis.Prefix, item.Basis.LocalName, item.Basis.Namespace, null);
            navigator.MoveToChild(item.Basis.LocalName, item.Basis.Namespace);
            while (navigator.MoveToNext())
            {                
            }

            return navigator;            
        }

        /// <summary>
        /// Appends left elements 
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <param name="parent">
        /// The parent node.
        /// </param>
        internal static void AppendLeftElements(this OffspringItem item, IXPathNavigable parent)
        {
            if (item.LeftNodes() == null)
            {
                return;
            }

            foreach (XPathNavigator navigator in item.LeftNodes())
            {
                parent.CreateNavigator().AppendChild(navigator.Clone());
            }
        }

        /// <summary>
        /// gets the left nodes of the item.
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <returns>
        /// the collection of left nodes
        /// </returns>
        internal static Collection<XPathNavigator> LeftNodes(this OffspringItem item)
        {
            return item.Basis.Root.LeftNodesDictionary.ContainsKey(item.UniqueID)
                           ? item.Basis.Root.LeftNodesDictionary[item.UniqueID]
                           : null;
        }
    }
}